import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:my_flutter_core/extensions/string_extension.dart';
import 'package:my_flutter_core/models/user.dart';
import 'package:my_flutter_core/services/auth_state_service.dart';
import 'package:my_flutter_core/services/route_map_config_service.dart';
import 'package:my_flutter_core/services/route_map_manager.dart';
import 'package:my_flutter_core/utils/ui_interaction_utils.dart';

/// Flutter official suggests using go_router instead of navigator.
///
/// Navigation related actions, like check open route, navigating with extra route guard check and etc.
/// Some methods just call [Navigator] directly by now. The extra logic can be applied if needed.
class NavigatorHelper {
  /// Gets the modal route that replaces the entire screen.
  /// Based on your needs you can choose to return [MaterialPageRoute] or [CupertinoPageRoute].
  ///
  /// The parameter [title] only works for [CupertinoPageRoute] type.
  static PageRoute<T> getPageRoute<T>({
    required WidgetBuilder builder,
    String? title,
    RouteSettings? settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
  }) {
    // Option1, MaterialPageRoute.
    return MaterialPageRoute<T>(
      builder: builder,
      settings: settings,
      maintainState: maintainState,
      fullscreenDialog: fullscreenDialog,
    );

    // Option2, CupertinoPageRoute.
    //    return CupertinoPageRoute<T>(
    //      builder: builder,
    //      title: title,
    //      settings: settings,
    //      maintainState: maintainState,
    //      fullscreenDialog: fullscreenDialog,
    //    );
  }

  /// Push the given route onto the navigator.
  /// It calls[Navigator.push] with extra route guard check.
  static Future<T?> push<T extends Object?>(
    BuildContext context,
    Widget widget,
  ) async {
    // Satisfies "Do not use BuildContexts across async gaps".
    // https://github.com/flutter/flutter/issues/110694
    final navigator = Navigator.of(context);

    if (_checkCanActivate(
      widget,
      user: await AuthStateService.instance.currentUser,
    )) {
      return navigator.push<T>(getPageRoute(builder: (context) => widget));
    } else {
      return Future.value();
    }
  }

  /// Replace the current route of the navigator by pushing the given route and
  /// then disposing the previous route once the new route has finished
  /// animating in.
  /// It calls[Navigator.pushReplacement] with extra route guard checking.
  static Future<T?> pushReplacement<T extends Object?, TO extends Object?>(
    BuildContext context,
    Widget widget, {
    TO? result,
  }) async {
    // Satisfies "Do not use BuildContexts across async gaps".
    // https://github.com/flutter/flutter/issues/110694
    final navigator = Navigator.of(context);

    if (_checkCanActivate(
      widget,
      user: await AuthStateService.instance.currentUser,
    )) {
      return navigator.pushReplacement<T, TO>(
        getPageRoute(builder: (context) => widget),
        result: result,
      );
    } else {
      return Future.value();
    }
  }

  /// Push the given route onto the navigator, and then remove all the previous
  /// routes until the `predicate` returns true.
  /// It calls[Navigator.pushAndRemoveUntil] with extra route guard checking.
  static Future<T?> pushAndRemoveUntil<T extends Object?>(
    BuildContext context,
    Widget widget,
    RoutePredicate predicate,
  ) async {
    // Satisfies "Do not use BuildContexts across async gaps".
    // https://github.com/flutter/flutter/issues/110694
    final navigator = Navigator.of(context);

    if (_checkCanActivate(
      widget,
      user: await AuthStateService.instance.currentUser,
    )) {
      return navigator.pushAndRemoveUntil<T>(
        getPageRoute(builder: (context) => widget),
        predicate,
      );
    } else {
      return Future.value();
    }
  }

  /// Whether the navigator that most tightly encloses the given context can be
  /// popped.
  static bool canPop(BuildContext context) {
    return Navigator.canPop(context);
  }

  /// Returns the value of the current route's Route.willPop method for the
  /// navigator that most tightly encloses the given context.
  static Future<bool> maybePop<T extends Object?>(
    BuildContext context, [
    T? result,
  ]) {
    return Navigator.maybePop<T>(context, result);
  }

  /// Pops the top-most route off the navigator that most tightly encloses the
  /// given context.
  static void pop<T extends Object?>(BuildContext context, [T? result]) {
    Navigator.pop<T>(context, result);
  }

  /// Calls [pop] repeatedly on the navigator that most tightly encloses the
  /// given context until the predicate returns true.
  static void popUntil(BuildContext context, RoutePredicate predicate) {
    Navigator.popUntil(context, predicate);
  }

  /// Immediately removes `route` from the navigator that most tightly encloses
  /// the given context, and [Route.dispose] it.
  static void removeRoute(BuildContext context, Route<dynamic> route) {
    return Navigator.removeRoute(context, route);
  }

  /// Immediately removes a route from the navigator that most tightly encloses
  /// the given context, and [Route.dispose] it. The route to be replaced is the
  /// one below the given `anchorRoute`.
  static void removeRouteBelow(
    BuildContext context,
    Route<dynamic> anchorRoute,
  ) {
    return Navigator.removeRouteBelow(context, anchorRoute);
  }

  /// Checks if the provided route can be activated.
  /// The route can be activated only when it is open route or current user is authenticated.
  /// If cannot activate the route then will be redirected to the [PasswordLogin].
  static bool _checkCanActivate(Widget widget, {User? user}) {
    // Gets route map config by route name.
    final routeConfig = RouteMapConfigService.getNavigatorConfigAttribute(
      widget,
    );

    var canActivate = false;

    if (routeConfig.isNotNullOrEmpty) {
      // Validates route access permission.
      canActivate = RouteMapManager.checkRouteOnConfigAttribute(
        user,
        routeConfig!,
      );
    }

    if (!canActivate) {
      showToast('对不起，您当前账号没有权限使用该功能，您可以尝试以其它账号重新登录。');
    }

    return canActivate;
  }
}
